package com.ssy.lingxi.contract.serviceimpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.constant.contract.ContractSourceTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.contract.api.model.vo.request.ContrPriceQueryRequest;
import com.ssy.lingxi.contract.api.model.vo.request.ContractPageRequest;
import com.ssy.lingxi.contract.api.model.vo.response.ContractPageResponse;
import com.ssy.lingxi.contract.api.model.vo.response.ContractPriceQueryVO;
import com.ssy.lingxi.contract.entity.ContractDO;
import com.ssy.lingxi.contract.entity.ContractPurchaseMaterielDO;
import com.ssy.lingxi.contract.entity.QContractDO;
import com.ssy.lingxi.contract.entity.QContractPurchaseMaterielDO;
import com.ssy.lingxi.contract.model.constant.*;
import com.ssy.lingxi.contract.model.vo.common.response.ApplyAmountOrderListVO;
import com.ssy.lingxi.contract.model.vo.common.response.ContractTextVO;
import com.ssy.lingxi.contract.model.vo.common.response.PageItemVO;
import com.ssy.lingxi.contract.model.vo.common.response.TaskStepVO;
import com.ssy.lingxi.contract.model.vo.coordination.request.AssociatedGoodsUpdateVO;
import com.ssy.lingxi.contract.model.vo.coordination.request.ContractCoordinationCommonPageVO;
import com.ssy.lingxi.contract.model.vo.coordination.request.ContractCoordinationExamineVO;
import com.ssy.lingxi.contract.model.vo.coordination.request.ContractCoordinationPageVO;
import com.ssy.lingxi.contract.model.vo.coordination.response.ContractCoordinationBasicsVO;
import com.ssy.lingxi.contract.model.vo.coordination.response.ContractCoordinationDetailVO;
import com.ssy.lingxi.contract.model.vo.coordination.response.ContractCoordinationQueryVO;
import com.ssy.lingxi.contract.repository.ContractRepository;
import com.ssy.lingxi.contract.service.*;
import com.ssy.lingxi.dto.request.ApplyAmountSunQueryVO;
import com.ssy.lingxi.dto.response.ApplyAmountSunVO;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.message.api.vo.request.SystemMessageRequest;
import com.ssy.lingxi.report.api.enums.ContractCoordinationOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.ContractManageOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleTaskCompleteVO;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.ssy.lingxi.contract.entity.QContractDO.contractDO;

/**
 * 合同协作接口实现
 * @author 伍将
 * @date 2021/2/3
 * @version 2.0.0
 */
@Service
public class ContractCoordinationServiceImpl implements IContractCoordinationService {

    @Resource
    private ContractRepository repository;

    @Resource
    private IContractInnerRecordService innerRecordService;

    @Resource
    private IContractOuterRecordService outerRecordService;

    @Resource
    private IApplyAmountOrderService applyAmountOrderService;

    @Resource
    private IContractTextService contractTextService;

    @Resource
    private IContractPurchaseMaterielService purchaseMaterielService;

    @Resource
    private IProcessFeignService processFeignService;
    @Resource
    private IFeignService feignService;
    @Resource
    private JPAQueryFactory jpaQueryFactory;

    /**
     * 分页查询合同列表
     * @author 伍将
     * @date 2021/2/3
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ContractCoordinationQueryVO>> pageList(UserLoginCacheDTO user, ContractCoordinationPageVO pageVO) {
        return commonPageList(user, pageVO, null, null);
    }

    /**
     * 查询合同详情
     * @author 伍将
     * @date 2021/2/8
     * @param user: 当前登录用户
     * @param contractId: 合同id
     * @return 操作结果
     **/
    @Override
    public Wrapper<ContractCoordinationDetailVO> getDetail(UserLoginCacheDTO user, Long contractId) {

        ContractCoordinationDetailVO result = new ContractCoordinationDetailVO();

        ContractDO contract = repository.findById(contractId).orElse(null);
        if (null == contract) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_EXIST);
        }else if(!contract.getPartyBMemberId().equals(user.getMemberId())||!contract.getPartyBRoleId().equals(user.getMemberRoleId())){
            throw new BusinessException(ResponseCode.CONTRACT_NOT_EXIST);
        }

        // 获取合同基本信息
        ContractCoordinationBasicsVO basics = new ContractCoordinationBasicsVO();
        basics.setId(contractId);
        basics.setContractNo(contract.getContractNo());
        basics.setOuterStatus(contract.getOuterStatus());
        basics.setOuterStatusName(ContractOuterStatusEnum.getMessage(contract.getOuterStatus()));
        basics.setInnerStatus(contract.getPartyBInnerStatus());
        basics.setInnerStatusName(ContractPartyBInnerStatusEnum.getMessage(contract.getPartyBInnerStatus()));
        basics.setContractAbstract(contract.getContractAbstract());
        basics.setSourceType(contract.getSourceType());
        basics.setSourceTypeName(ContractSourceTypeEnum.getNameByCode(contract.getSourceType()));
        basics.setSourceId(contract.getSourceId());
        basics.setSourceNo(contract.getSourceNo());
        basics.setPartyAName(contract.getPartyAName());
        basics.setTotalAmount(contract.getTotalAmount());
        basics.setStartTime(DateUtil.format(DateUtil.date(contract.getStartTime()), "yyyy-MM-dd"));
        basics.setEndTime(DateUtil.format(DateUtil.date(contract.getEndTime()), "yyyy-MM-dd"));
        basics.setSignatureLogId(contract.getSignatureLogId());
        basics.setTurn(contract.getTurn());
        result.setBasics(basics);

        // 获取外部流转步骤
        List<TaskStepVO> outerTaskList = processFeignService.listTaskStepOut(contract.getOuterTaskType(),contract.getOuterTaskId(),contract.getPartyARoleId(),contract.getPartyBRoleId());
        result.setOuterTaskStepList(outerTaskList);

        // 获取内部流转步骤
        List<TaskStepVO> innerTaskList = processFeignService.listTaskStep(contract.getPartyBInnerTaskType(),contract.getPartyBInnerTaskId(),contract.getPartyBMemberId());
        result.setInnerTaskStepList(innerTaskList);

        // 合同付款情况统计
        // 组装远端调用请求
        boolean partyAFlag = contract.getPartyAMemberId().equals(user.getMemberId()) && contract.getPartyARoleId().equals(user.getMemberRoleId());
        ApplyAmountSunQueryVO queryVO = new ApplyAmountSunQueryVO();
        queryVO.setContractId(contractId);
        queryVO.setPartyAFlag(partyAFlag);
        Wrapper<List<ApplyAmountSunVO>> helpList = feignService.listForPaySummaryByParty(queryVO);
        if (helpList.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(helpList.getCode());
        }
        // 组装数据
        AtomicReference<Long> helpPayNum = new AtomicReference<>(1L);
        List<ApplyAmountOrderListVO> applyAmountOrderListVOS = helpList.getData().stream().map(map -> {
            ApplyAmountOrderListVO item = new ApplyAmountOrderListVO();
            item.setId(map.getId());
            item.setApplyAmountNo(map.getApplyNo());
            item.setPayNum(Math.toIntExact(helpPayNum.getAndSet(helpPayNum.get() + 1)));
            item.setPayStage(map.getApplyAbstract());
            item.setPayTime(Optional.ofNullable(map.getPayTime()).filter(StringUtils::hasText).map(map1 -> DateUtil.parse(map1, "yyyy-MM-dd HH:mm")).map(Date::getTime).orElse(null));
            item.setPayAmount(map.getPayAmount());
            item.setPayWayName(map.getPayWayName());
//            item.setPayParam(0);
            item.setSourceType(2);
            item.setPaidRatio(NumberUtil.div(BigDecimal.valueOf(item.getPayAmount()), BigDecimal.valueOf(contract.getTotalAmount()),4, RoundingMode.HALF_UP).multiply(new BigDecimal(100)));
            return item;
        }).collect(Collectors.toList());
        result.setApplyAmountOrderList(applyAmountOrderListVOS);
        // 获取合同文本
        Wrapper<ContractTextVO> textWrapper = contractTextService.getDetail(contractId);
        if (null == textWrapper || textWrapper.getCode() != ResponseCode.SUCCESS.getCode()) {
            throw new BusinessException(ResponseCode.CONTRACT_GET_OUTER_RECORD_ERROR);
        }
        result.setContractText(textWrapper.getData());

        return Wrapper.success(result);
    }

    /**
     * 分页查询待提交审核合同列表
     * @author 伍将
     * @date 2021/2/3
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ContractCoordinationQueryVO>> pageToBeSubmitExamine(UserLoginCacheDTO user, ContractCoordinationCommonPageVO pageVO) {
        ContractCoordinationPageVO managePageVO = new ContractCoordinationPageVO();
        BeanUtils.copyProperties(pageVO, managePageVO);
        managePageVO.setOuterStatus(ContractOuterStatusEnum.TO_BE_PARTY_B_SIGN_CONTRACT.getCode());
        managePageVO.setInnerStatus(ContractPartyBInnerStatusEnum.TO_BE_SUBMIT_EXAMINE.getCode());
        return commonPageList(user, managePageVO, null, null);
    }

    /**
     * 关联报价商品
     * @author 伍将
     * @date 2021/3/2
     * @param user: 当前登录用户
     * @param updateVO: 更新参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<Void> associatedOfferGoods(UserLoginCacheDTO user, AssociatedGoodsUpdateVO updateVO) {
        // 检查合同是否存在
        ContractDO contract = repository.findById(updateVO.getContractId()).orElse(null);
        if (null == contract) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_EXIST);
        }

        // 外部状态为待已方签订合同、内部状态为待提交审核合同，才允许修改关联报价商品
        if (!ContractOuterStatusEnum.TO_BE_PARTY_B_SIGN_CONTRACT.getCode().equals(contract.getOuterStatus())
                || !ContractPartyBInnerStatusEnum.TO_BE_SUBMIT_EXAMINE.getCode().equals(contract.getPartyBInnerStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_ALLOW_UPDATE_ASSOCIATED_GOODS);
        }
        // 更新采购物料
        return purchaseMaterielService.update(updateVO);
    }

    /**
     * 提交审核
     * @author 伍将
     * @date 2021/2/8
     * @param user:当前登录用户
     * @param examineVO:审核请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> submitExamine(UserLoginCacheDTO user, ContractCoordinationExamineVO examineVO) {

        // 检查审核参数
        ContractDO contract = checkExamineParam(examineVO);

        // 外部状态为待已方签订合同、内部状态为待提交审核合同，才允许提交审核
        if (!ContractOuterStatusEnum.TO_BE_PARTY_B_SIGN_CONTRACT.getCode().equals(contract.getOuterStatus())
                || !ContractPartyBInnerStatusEnum.TO_BE_SUBMIT_EXAMINE.getCode().equals(contract.getPartyBInnerStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_ALLOW_EXAMINE);
        }
        //校验物料是否关联商品
        /*Boolean flag = purchaseMaterielService.checkContractAssociatedGoods(contract.getId());
        if(!flag){
            throw new BusinessException(ResponseCode.CONTRACT_NOT_HAVE_ASSOCIATED_GOODS);
        }*/

        // 执行工作流
        contract = processFeignService.completeSimpleTaskByContractPartyBInner(contract, examineVO.getIsPass());
        String statusName=ContractPartyBInnerStatusEnum.getMessage(contract.getPartyBInnerStatus());
        contract.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(contract);

        // 新增内部流转记录
        innerRecordService.add(user, contract.getId(), contract.getPartyBInnerStatus(), statusName, ContractActionEnum.SUBMIT_VALIFY.getMessage(), examineVO.getOpinion());
        //待提交审核合同-1，待审核合同（一级）+1
        addNotice(contract,ContractCoordinationOperateTypeEnum.TO_BE_COMMIT_VALIFY,ContractCoordinationOperateTypeEnum.TO_BE_VALIFY_STEP1);
        //发送消息
        sendContractSystemMessageInner(contract, MessageTemplateCode.contract_synergy_audit_step_1);
        return Wrapper.success();
    }

    private void addNotice(ContractDO contract,ContractCoordinationOperateTypeEnum reduceOperateType,ContractCoordinationOperateTypeEnum increaseOperateType){
        OperateNoticeVO addNoticeVO = new OperateNoticeVO();
        addNoticeVO.setMemberId(contract.getPartyBMemberId());
        addNoticeVO.setRoleId(contract.getPartyBRoleId());
        addNoticeVO.setDataSource(OperateDataSourceEnum.CONTRACT_COORDINATION.getCode());
        if(increaseOperateType!=null) {
            addNoticeVO.setIncreaseCount(com.ssy.lingxi.contract.constant.Constants.SYS_OPERATE_NOTICE_COUNT);
            addNoticeVO.setIncreaseDataId(contract.getId());
            addNoticeVO.setIncreaseOperateType(increaseOperateType.getCode());
            addNoticeVO.setIncreaseTitle(contract.getContractAbstract());
        }
        if(reduceOperateType!=null) {
            addNoticeVO.setReduceCount(com.ssy.lingxi.contract.constant.Constants.SYS_OPERATE_NOTICE_COUNT);
            addNoticeVO.setReduceDataId(contract.getId());
            addNoticeVO.setReduceOperateType(reduceOperateType.getCode());
        }
        feignService.addSysOperateNoticeToMQ(addNoticeVO);
    }
    //添加系统操作通知-mq

    /**
     * 分页查询待审核一级合同列表
     * @author 伍将
     * @date 2021/2/3
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ContractCoordinationQueryVO>> pageToBeExamineOne(UserLoginCacheDTO user, ContractCoordinationCommonPageVO pageVO) {
        ContractCoordinationPageVO managePageVO = new ContractCoordinationPageVO();
        BeanUtils.copyProperties(pageVO, managePageVO);
        managePageVO.setOuterStatus(ContractOuterStatusEnum.TO_BE_PARTY_B_SIGN_CONTRACT.getCode());
        managePageVO.setInnerStatus(ContractPartyBInnerStatusEnum.TO_BE_EXAMINE_1.getCode());
        return commonPageList(user, managePageVO, null, null);
    }

    /**
     * 一级审核
     * @author 伍将
     * @date 2021/2/8
     * @param user:当前登录用户
     * @param examineVO:审核请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> examineStepOne(UserLoginCacheDTO user, ContractCoordinationExamineVO examineVO) {

        // 检查审核参数
        ContractDO contract = checkExamineParam(examineVO);

        // 外部状态为待已方签订合同、内部状态为待审核合同(一级)，才允许审核合同(一级)
        if (!ContractOuterStatusEnum.TO_BE_PARTY_B_SIGN_CONTRACT.getCode().equals(contract.getOuterStatus())
                || !ContractPartyBInnerStatusEnum.TO_BE_EXAMINE_1.getCode().equals(contract.getPartyBInnerStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_ALLOW_EXAMINE);
        }

        // 执行工作流
        contract = processFeignService.completeSimpleTaskByContractPartyBInner(contract, examineVO.getIsPass());
        String statusName=ContractPartyBInnerStatusEnum.getMessage(contract.getPartyBInnerStatus());
        contract.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(contract);

        // 新增内部流转记录
        innerRecordService.add(user, contract.getId(), contract.getPartyBInnerStatus(), statusName, ContractActionEnum.EXAMINE_1.getMessage(), examineVO.getOpinion());
        //待审核合同（一级）-1,待审核合同（二级）+1
        addNotice(contract,ContractCoordinationOperateTypeEnum.TO_BE_VALIFY_STEP1,ContractCoordinationOperateTypeEnum.TO_BE_VALIFY_STEP2);
        //发送消息
        sendContractSystemMessageInner(contract, MessageTemplateCode.contract_synergy_audit_step_2);
        return Wrapper.success();
    }

    /**
     * 分页查询待审核二级合同列表
     * @author 伍将
     * @date 2021/2/3
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ContractCoordinationQueryVO>> pageToBeExamineTwo(UserLoginCacheDTO user, ContractCoordinationCommonPageVO pageVO) {
        ContractCoordinationPageVO managePageVO = new ContractCoordinationPageVO();
        BeanUtils.copyProperties(pageVO, managePageVO);
        managePageVO.setOuterStatus(ContractOuterStatusEnum.TO_BE_PARTY_B_SIGN_CONTRACT.getCode());
        managePageVO.setInnerStatus(ContractPartyBInnerStatusEnum.TO_BE_EXAMINE_2.getCode());
        return commonPageList(user, managePageVO, null, null);
    }

    /**
     * 二级级审核
     * @author 伍将
     * @date 2021/2/8
     * @param user:当前登录用户
     * @param examineVO:审核请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> examineStepTwo(UserLoginCacheDTO user, ContractCoordinationExamineVO examineVO) {

        // 检查审核参数
        ContractDO contract = checkExamineParam(examineVO);

        // 外部状态为待已方签订合同、内部状态为待审核合同(二级)，才允许审核合同(二级)
        if (!ContractOuterStatusEnum.TO_BE_PARTY_B_SIGN_CONTRACT.getCode().equals(contract.getOuterStatus())
                || !ContractPartyBInnerStatusEnum.TO_BE_EXAMINE_2.getCode().equals(contract.getPartyBInnerStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_ALLOW_EXAMINE);
        }

        // 执行工作流
        contract = processFeignService.completeSimpleTaskByContractPartyBInner(contract, examineVO.getIsPass());
        String statusName=ContractPartyBInnerStatusEnum.getMessage(contract.getPartyBInnerStatus());
        contract.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(contract);

        // 新增内部流转记录
        innerRecordService.add(user, contract.getId(), contract.getPartyBInnerStatus(), statusName, ContractActionEnum.EXAMINE_2.getMessage(), examineVO.getOpinion());
        //待审核合同（二级）-1，待签订合同+1
        addNotice(contract,ContractCoordinationOperateTypeEnum.TO_BE_VALIFY_STEP2,ContractCoordinationOperateTypeEnum.TO_BE_SIGN);
        //发送消息
        sendContractSystemMessageInner(contract, MessageTemplateCode.contract_synergy_wait_sign);
        return Wrapper.success();
    }

    /**
     * 分页查询待签订合同列表
     * @author 伍将
     * @date 2021/2/3
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ContractCoordinationQueryVO>> pageToBeSign(UserLoginCacheDTO user, ContractCoordinationCommonPageVO pageVO) {
        ContractCoordinationPageVO managePageVO = new ContractCoordinationPageVO();
        BeanUtils.copyProperties(pageVO, managePageVO);
        managePageVO.setOuterStatus(ContractOuterStatusEnum.TO_BE_PARTY_B_SIGN_CONTRACT.getCode());
        List<Integer> innerStatusList = new ArrayList<>();
        innerStatusList.add(ContractPartyBInnerStatusEnum.SUBMIT_EXAMINE_NO_PASS.getCode());
        innerStatusList.add(ContractPartyBInnerStatusEnum.EXAMINE_NO_PASS_1.getCode());
        innerStatusList.add(ContractPartyBInnerStatusEnum.EXAMINE_PASS_2.getCode());
        innerStatusList.add(ContractPartyBInnerStatusEnum.EXAMINE_NO_PASS_2.getCode());
        return commonPageList(user, managePageVO, null, innerStatusList);
    }

    /**
     * 签订合同
     * @author 伍将
     * @date 2021/2/8
     * @param user: 当前登录用户
     * @param examineVO: 审核请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> sign(UserLoginCacheDTO user, ContractCoordinationExamineVO examineVO) {

        // 检查审核参数
        ContractDO contract = checkExamineParam(examineVO);

        // 外部状态为待乙方签订合同、内部状态为待提交审核合同，才允许提交审核
        if (!ContractOuterStatusEnum.TO_BE_PARTY_B_SIGN_CONTRACT.getCode().equals(contract.getOuterStatus())
                && !ContractPartyBInnerStatusEnum.EXAMINE_PASS_2.getCode().equals(contract.getPartyBInnerStatus())
                && !ContractPartyBInnerStatusEnum.EXAMINE_NO_PASS_2.getCode().equals(contract.getPartyBInnerStatus())
                && !ContractPartyBInnerStatusEnum.SUBMIT_EXAMINE_NO_PASS.getCode().equals(contract.getPartyBInnerStatus())
                && !ContractPartyBInnerStatusEnum.EXAMINE_NO_PASS_1.getCode().equals(contract.getPartyBInnerStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_ALLOW_SIGN);
        }

        // 只有当内部状态为审核通过(二级)时，才允许选择同意签订
        if (CommonBooleanEnum.YES.getCode().equals(examineVO.getIsPass())
                && !ContractPartyBInnerStatusEnum.EXAMINE_PASS_2.getCode().equals(contract.getPartyBInnerStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_ALLOW_SIGN);
        }

        // 执行乙方内部工作流
        contract = processFeignService.completeSimpleTaskByContractPartyBInner(contract, examineVO.getIsPass());
        String innerStatusName=ContractPartyBInnerStatusEnum.getMessage(contract.getPartyBInnerStatus());
        // 新增内部流转记录
        innerRecordService.add(user, contract.getId(), contract.getPartyBInnerStatus(), innerStatusName, ContractActionEnum.SIGN.getMessage(), examineVO.getOpinion());

        // 执行外部工作流
        contract = processFeignService.completeSimpleTaskByContractOuter(contract, examineVO.getIsPass());
        String outerStatusName=ContractOuterStatusEnum.getMessage(contract.getOuterStatus());
        // 新增外部流转记录
        outerRecordService.add(user, contract.getId(), contract.getOuterStatus(), outerStatusName,ContractActionEnum.SIGN_PARTY_B.getMessage() , examineVO.getOpinion());

        // 乙方同意签订合同，启动甲方内部工作流
        if (ContractOuterStatusEnum.TO_BE_PARTY_A_SIGN_CONTRACT.getCode().equals(contract.getOuterStatus())) {
            SimpleTaskCompleteVO taskResult = processFeignService.startSimpleProcess(contract.getPartyAMemberId(), contract.getPartyARoleId(), contract.getPartyAInnerTaskType(), contract.getId());
            contract.setPartyAInnerTaskId(taskResult.getTaskId());
            contract.setPartyAInnerTaskStep(taskResult.getStep());
            // 乙方同意签订合同下，更改甲方内部状态为：待提交审核合同
            contract.setPartyAInnerStatus(taskResult.getStatus());
        }
        //保存合同文件
        if(StringUtils.hasLength(examineVO.getContractUrl())) {
            contractTextService.updateUrlById(contract.getId(),examineVO.getContractUrl());
        }

        // 保存合同信息
        contract.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(contract);

        // 待签订合同-1
        OperateNoticeVO noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(contract.getPartyBMemberId());
        noticeVO.setRoleId(contract.getPartyBRoleId());
        noticeVO.setDataSource(OperateDataSourceEnum.CONTRACT_COORDINATION.getCode());
        noticeVO.setReduceCount(com.ssy.lingxi.contract.constant.Constants.SYS_OPERATE_NOTICE_COUNT);
        noticeVO.setReduceDataId(contract.getId());
        noticeVO.setReduceOperateType(ContractCoordinationOperateTypeEnum.TO_BE_SIGN.getCode());
        //待甲方签订合同+1
        OperateNoticeVO addNoticeVO = new OperateNoticeVO();
        addNoticeVO.setMemberId(contract.getPartyAMemberId());
        addNoticeVO.setRoleId(contract.getPartyARoleId());
        addNoticeVO.setDataSource(OperateDataSourceEnum.CONTRACT_MANAGE.getCode());
        addNoticeVO.setIncreaseCount(com.ssy.lingxi.contract.constant.Constants.SYS_OPERATE_NOTICE_COUNT);
        addNoticeVO.setIncreaseDataId(contract.getId());
        addNoticeVO.setIncreaseOperateType(ContractManageOperateTypeEnum.TO_BE_COMMIT_VALIFY.getCode());
        addNoticeVO.setIncreaseTitle(contract.getContractAbstract());
        feignService.addSysOperateNoticeToMQ(Stream.of(noticeVO,addNoticeVO).collect(Collectors.toList()));
        //发送消息
        sendContractSystemMessageOuter(contract, MessageTemplateCode.contract_manage_wait_audit);
        return Wrapper.success();
    }

    /**
     *  公共分页查询合同列表方法
     * @author 伍将
     * @date 2021/2/3
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @param outerStatusList: 外部状态列表
     * @param innerStatusList: 内部状态列表
     * @return 操作结果
     **/
    private Wrapper<PageData<ContractCoordinationQueryVO>> commonPageList(UserLoginCacheDTO user, ContractCoordinationPageVO pageVO, List<Integer> outerStatusList, List<Integer> innerStatusList) {

        // 组装查询条件
        Specification<ContractDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("partyBMemberId").as(Long.class), user.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("partyBRoleId").as(Long.class), user.getMemberRoleId()));
            list.add(criteriaBuilder.equal(root.get("isSubmit").as(Long.class), CommonBooleanEnum.YES.getCode()));
            // 组装外部状态条件
            if (null != outerStatusList && outerStatusList.size() > 0) {
                list.add(criteriaBuilder.in(root.get("outerStatus")).value(outerStatusList));
            } else {
                if (!ContractOuterStatusEnum.ALL.getCode().equals(pageVO.getOuterStatus())) {
                    list.add(criteriaBuilder.equal(root.get("outerStatus").as(Integer.class), pageVO.getOuterStatus()));
                }
            }
            // 组装内部状态条件
            if (null != innerStatusList && innerStatusList.size() > 0) {
                list.add(criteriaBuilder.in(root.get("partyBInnerStatus")).value(innerStatusList));
            } else {
                if (!ContractPartyAInnerStatusEnum.ALL.getCode().equals(pageVO.getInnerStatus())) {
                    list.add(criteriaBuilder.equal(root.get("partyBInnerStatus").as(Integer.class), pageVO.getInnerStatus()));
                }
            }
            if (StringUtils.hasLength(pageVO.getStartTime())) {
                list.add(criteriaBuilder.greaterThan(root.get("startTime").as(Long.class), DateUtil.parse(pageVO.getStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getEndTime())) {
                list.add(criteriaBuilder.lessThan(root.get("endTime").as(Long.class), DateUtil.parse(pageVO.getEndTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getContractNo())) {
                list.add(criteriaBuilder.like(root.get("contractNo").as(String.class), "%" + pageVO.getContractNo().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getContractAbstract())) {
                list.add(criteriaBuilder.like(root.get("contractAbstract").as(String.class), "%" + pageVO.getContractAbstract().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getPartyAName())) {
                list.add(criteriaBuilder.like(root.get("partyAName").as(String.class), "%" + pageVO.getPartyAName().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("startTime").descending());

        Page<ContractDO> result = repository.findAll(spec, page);
        List<ContractCoordinationQueryVO> resultList = result.getContent().stream().map(o -> {
            ContractCoordinationQueryVO entity = new ContractCoordinationQueryVO();
            entity.setId(o.getId());
            entity.setContractNo(o.getContractNo());
            entity.setContractAbstract(o.getContractAbstract());
            entity.setStartTime(DateUtil.format(DateUtil.date(o.getStartTime()), "yyyy-MM-dd"));
            entity.setEndTime(DateUtil.format(DateUtil.date(o.getEndTime()), "yyyy-MM-dd"));
            entity.setPartyAName(o.getPartyAName());
            entity.setTotalAmount(o.getTotalAmount());
            entity.setSourceType(o.getSourceType());
            entity.setSourceTypeName(ContractSourceTypeEnum.getNameByCode(o.getSourceType()));
            entity.setSourceId(o.getSourceId());
            entity.setSourceNo(o.getSourceNo());
            entity.setOuterStatus(o.getOuterStatus());
            entity.setOuterStatusName(ContractOuterStatusEnum.getMessage(o.getOuterStatus()));
            entity.setInnerStatus(o.getPartyBInnerStatus());
            entity.setInnerStatusName(ContractPartyBInnerStatusEnum.getMessage(o.getPartyBInnerStatus()));
            entity.setSignatureLogId(o.getSignatureLogId());
            return entity;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 检查审核参数
     * @author 伍将
     * @date 2021/2/8
     * @param examineVO: 审核请求参数
     * @return 合同
     **/
    private ContractDO checkExamineParam(ContractCoordinationExamineVO examineVO) {

        // 验证审核参数
        if (!CommonBooleanEnum.NO.getCode().equals(examineVO.getIsPass()) && !CommonBooleanEnum.YES.getCode().equals(examineVO.getIsPass())) {
            throw new BusinessException(ResponseCode.CONTRACT_EXAMINE_PARAM_ERROR);
        }
        // 审核原因不能为空
        if (CommonBooleanEnum.NO.getCode().equals(examineVO.getIsPass()) && !StringUtils.hasLength(examineVO.getOpinion())) {
            throw new BusinessException(ResponseCode.CONTRACT_EXAMINE_OPINION_EMPTY);
        }

        ContractDO contract = repository.findById(examineVO.getContractId()).orElse(null);
        if (null == contract) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_EXIST);
        }

        return contract;
    }


    /**
     * 获取外部状态列表
     * @author 伍将
     * @date 2021/2/3
     * @return 操作结果
     **/
    @Override
    public Wrapper<List<PageItemVO>> getOuterStatusList() {
        return Wrapper.success(Arrays.stream(ContractOuterStatusEnum.values()).map(r -> {
                    PageItemVO status = new PageItemVO();
                    status.setStatus(r.getCode());
                    status.setName(r.getMessage());
                    return status;
                }).collect(Collectors.toList())
        );
    }

    /**
     * 获取内部状态列表
     * @author 伍将
     * @date 2021/2/3
     * @return 操作结果
     **/
    @Override
    public Wrapper<List<PageItemVO>> getInnerStatusList() {
        return Wrapper.success(Arrays.stream(ContractPartyBInnerStatusEnum.values()).map(r -> {
                    PageItemVO status = new PageItemVO();
                    status.setStatus(r.getCode());
                    status.setName(r.getMessage());
                    return status;
                }).collect(Collectors.toList())
        );
    }

    /**
     * 发送合同模板消息-外部
     * @param contractDO 合同
     * @param messageTemplateCode 消息模板代码
     */
    private void sendContractSystemMessageOuter(ContractDO contractDO,String messageTemplateCode){
        SystemMessageRequest request = new SystemMessageRequest();
        request.setMemberId(contractDO.getPartyAMemberId());
        request.setRoleId(contractDO.getPartyARoleId());
        request.setMessageNotice(messageTemplateCode);
        request.setParams(Stream.of(contractDO.getContractNo(),contractDO.getContractAbstract()).collect(Collectors.toList()));
        feignService.sendSystemMessage(request);
    }
    /**
     * 发送合同模板消息-内部
     * @param contractDO 合同
     * @param messageTemplateCode 消息模板代码
     */
    private void sendContractSystemMessageInner(ContractDO contractDO,String messageTemplateCode){
        SystemMessageRequest request = new SystemMessageRequest();
        request.setMemberId(contractDO.getPartyBMemberId());
        request.setRoleId(contractDO.getPartyBRoleId());
        request.setMessageNotice(messageTemplateCode);
        request.setParams(Stream.of(contractDO.getContractNo(),contractDO.getContractAbstract()).collect(Collectors.toList()));
        feignService.sendSystemMessage(request);
    }

    @Override
    public Wrapper<PageData<ContractPageResponse>> pageContractByApplyAmount(ContractPageRequest pageVO) {

        // 查询表实体
        QContractDO contractDO= QContractDO.contractDO;
        QContractPurchaseMaterielDO contractPurchaseMaterielDO=QContractPurchaseMaterielDO.contractPurchaseMaterielDO;
        // 查询条件构造
        BooleanBuilder predicates = new BooleanBuilder();
        //状态
        predicates.and(contractDO.outerStatus.eq(ContractOuterStatusEnum.COMPLETE_SIGN_CONTRACT.getCode()));
        //合同编号
        if(StringUtils.hasLength(pageVO.getContractNo())){
            predicates.and(contractDO.contractNo.eq(pageVO.getContractNo()));
        }
        //时间
        if(pageVO.getStartTime()!=null){
            predicates.and(contractDO.startTime.goe(pageVO.getStartTime()));
        }
        if(pageVO.getEndTime()!=null){
            predicates.and(contractDO.endTime.loe(pageVO.getEndTime()));
        }
        //摘要
        if(StringUtils.hasLength(pageVO.getContractAbstract())){
            predicates.and(contractDO.contractAbstract.like("%" +pageVO.getContractAbstract()+"%"));
        }
        if(pageVO.getPartyBMemberId()!=null){
            predicates.and(contractDO.partyBMemberId.eq(pageVO.getPartyBMemberId()));
        }
        if(pageVO.getPartyBRoleId()!=null){
            predicates.and(contractDO.partyBRoleId.eq(pageVO.getPartyBRoleId()));
        }
        if(pageVO.getSourceType()!=null){
            predicates.and(contractDO.sourceType.eq(pageVO.getSourceType()));
        }
        // 关联查询
        JPAQuery<ContractPageResponse> query = jpaQueryFactory
                .select(Projections.bean(ContractPageResponse.class,
                        contractDO.id.as("contractId"),
                        contractDO.contractNo,
                        contractDO.contractAbstract,
                        contractDO.startTime,
                        contractDO.endTime,
                        contractDO.totalAmount,
                        contractPurchaseMaterielDO.isHasTax,
                        contractPurchaseMaterielDO.taxRate,
                        contractPurchaseMaterielDO.bidAmount.sum().as("taxAmount")
                        )
                )
                .from(contractDO)
                .innerJoin(contractPurchaseMaterielDO)
                .on(contractDO.id.eq(contractPurchaseMaterielDO.contractId))
                .where(predicates);
        query.groupBy(contractDO.id,contractPurchaseMaterielDO.isHasTax,contractPurchaseMaterielDO.taxRate);
        List<ContractPageResponse> responses = query.orderBy(contractDO.startTime.asc())
                .offset(pageVO.getCurrentOffset())
                .limit(pageVO.getPageSize())
                .fetch();
        JPAQuery<Long> total = jpaQueryFactory.select(contractDO.id)
                .from(contractDO)
                .innerJoin(contractPurchaseMaterielDO)
                .on(contractDO.id.eq(contractPurchaseMaterielDO.contractId))
                .where(predicates);
        List<Long> fetch = total.groupBy(contractDO.id, contractPurchaseMaterielDO.isHasTax, contractPurchaseMaterielDO.taxRate).fetch();
        return Wrapper.success(new PageData<>((long) fetch.size(), responses));
    }

    /**
     * 根据物料信息查询合同(商品能力- 物料价格库)
     * @author lxc
     * @date 2022/3/28
     **/
    @Override
    public Wrapper<ContractPriceQueryVO> goodsPriceByGoods(ContrPriceQueryRequest request) {
        String code = request.getCode();
        Long memberId = request.getMemberId();
        Long memberRoleId = request.getMemberRoleId();
        QContractPurchaseMaterielDO qMaterielDO = QContractPurchaseMaterielDO.contractPurchaseMaterielDO;
        QContractDO qContractDO = QContractDO.contractDO;
        BooleanBuilder predicates = new BooleanBuilder();
        predicates.and(qContractDO.partyAMemberId.eq(memberId));
        predicates.and(qContractDO.partyARoleId.eq(memberRoleId));
        //合同外部状态为已签约完成
        predicates.and(qContractDO.outerStatus.eq(ContractOuterStatusEnum.COMPLETE_SIGN_CONTRACT.getCode()));
        predicates.and(qMaterielDO.materielNo.eq(code));

        JPAQuery<ContractPriceQueryVO> query = jpaQueryFactory.select(
                Projections.bean(ContractPriceQueryVO.class,
                        qMaterielDO.materielNo.as("code"),
                        qMaterielDO.materielId.as("goodsId"),
                        qMaterielDO.price.as("totalAmount"),
                        qContractDO.contractNo,
                        qContractDO.startTime,
                        qContractDO.endTime,
                        qContractDO.partyBName,
                        qContractDO.partyBMemberId,
                        qContractDO.partyBRoleId))
                .from(qMaterielDO)
                .innerJoin(qContractDO)
                .on(qMaterielDO.contractId.eq(qContractDO.id))
                .where(predicates);
        List<ContractPriceQueryVO> queryVOS = query.fetch();
        if (CollectionUtils.isEmpty(queryVOS)){
            return Wrapper.success(null);
        }
        //筛选最新的合同信息
        ContractPriceQueryVO response = queryVOS.stream().max(Comparator.comparing(ContractPriceQueryVO::getStartTime)).orElse(null);
        return Wrapper.success(response);
    }
}

